package com.pig.sentinel.aop;

import com.pig.sentinel.SentinelResourceManager;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author lizhiwei
 */
@Aspect
@Component
@Slf4j
public class SentinelAop {

    @Autowired
    SentinelResourceManager sentinelResourceManager;

    @Pointcut("@annotation(com.pig.sentinel.annotions.Sentinel)")
    public void sentinelMethod() {
    }

    /**
     * 对带Sentinel注解的方法，进行切
     *
     * @param proceedingJoinPoint
     * @return
     */
    @Around("sentinelMethod()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Object target = proceedingJoinPoint.getTarget();
        sentinelResourceManager.analyzeMethod(target, method);
        boolean flowing = sentinelResourceManager.isFlowing(method);
        boolean degradeing = sentinelResourceManager.isDegradeing(method);
        if (flowing || degradeing) {
            Object[] args = proceedingJoinPoint.getArgs();
            ObjThreadLocal.set(new CurrentObj(target, args));
            return sentinelResourceManager.execExceptionHandler(method);
        }
        try {
            Object proceed = proceedingJoinPoint.proceed();
            sentinelResourceManager.execSuccess(method);
            return proceed;
        } catch (Throwable throwable) {
            sentinelResourceManager.incExceptionTimes(method);
            log.error("SentinelAop around degrade:");
            throw throwable;
        }
    }
}